﻿/******************************************************************************************
*                                                                                         *    
*                              Developed by Bruno Pires                                   *
*                                                                                         *
*                             email: bruno@blastersystems.com                             *
*                               web: www.blastersystems.com                               *
*                              blog: www.blastersystems.com/blog                          *
*                           twitter: @brunoacpires                                        *
*                                                                                         *
*             Software available under GNU LGPL v3 License without any guarantee          *
*                                                                                         *    
* *****************************************************************************************/ 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenNI;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Drawing;
using Pap.ExtensionHelper;

namespace Pap.Service.ImageRecorder
{
    public class PapRecorder
    {
        public event EventHandler GetNewFrame;
        private DispatcherTimer dispatcherTimer;
        private int nFrames = 0;

        private Context ctx;
        private Player player;
        private Recorder recorder;
        private DepthGenerator depth;
        private MockDepthGenerator mockDepth;

        public void StopRecorder()
        {
            if (recorder!=null)
            {
                recorder.RemoveNodeFromRecording(mockDepth);
                ctx.StopGeneratingAll();
            }
        }

        public void StopPlayer()
        {
            if (recorder!=null)
            {
                depth.StopGenerating();
                ctx.StopGeneratingAll();
                recorder.Dispose();
            }
            
        }

        public void Record(Context context, DepthGenerator generator, string destination)
        {
            ctx = context;
            depth = generator;
            recorder = ctx.FindExistingNode(NodeType.Recorder) as Recorder;
            recorder.SetDestination(RecordMedium.File, destination);
            
            mockDepth = new MockDepthGenerator(ctx, depth);
            recorder.AddNodeToRecording(mockDepth);
        }

        public void SaveData(DepthGenerator generator)
        {
            var metadata = generator.GetMetaData();
            mockDepth.SetData(metadata);
            recorder.Record();
        }

        public void LoadRecording(string recordingFile)
        {
            ctx = new Context();
            var pNode = ctx.OpenFileRecordingEx(recordingFile);
            player = ctx.FindExistingNode(NodeType.Player) as Player;
            depth = ctx.FindExistingNode(NodeType.Depth) as DepthGenerator;

            player.SetRepeat(false);
            nFrames = player.GetNumFrames(depth);

            if (depth != null)
            {
                depth.StartGenerating();
            }
            
            dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 10);
            dispatcherTimer.Start();

            player.EndOfFileReached += new EventHandler(player_EndOfFileReached);
        }

        void player_EndOfFileReached(object sender, EventArgs e)
        {
            dispatcherTimer.Tick -= dispatcherTimer_Tick;
        }

        public unsafe BitmapImage UpdateRecordingDepth( Bitmap depthBitmap)
        {
            try
            {
                if (depthBitmap == null)
                {
                    depthBitmap = new Bitmap(640, 480);
                }

                var generator = depth;
                var metadata = new DepthMetaData();

                var rect = new Rectangle(0, 0, depthBitmap.Width, depthBitmap.Height);
                var data = depthBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                generator.GetMetaData(metadata);


                ushort* pDepth = (ushort*)generator.DepthMapPtr.ToPointer();

                for (int i = 0; i < metadata.YRes; i++)
                {
                    byte* pDest = (byte*)data.Scan0.ToPointer() + i * data.Stride;

                    for (int j = 0; j < metadata.XRes; j++, pDepth++, pDest += 3)
                    {
                        pDest[0] = (byte)(*pDepth >> 0);
                        pDest[1] = (byte)(*pDepth >> 1);
                        pDest[2] = (byte)(*pDepth >> 2);
                    }
                }

                depthBitmap.UnlockBits(data);
                return depthBitmap.getBitmapImage();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            ctx.WaitNoneUpdateAll();

            if (recorder != null)
            {
                recorder.Record();
            }

            GetNewFrame(this, e);
        }
    }
}
